﻿using Microsoft.CodeAnalysis;
using System;

namespace DimensionsHelper.SourceGeneration
{

    internal static class KnownSymbolHelper
    {

        public const string SystemStringTypeFullName = "System.String";
        public const string SystemShortTypeFullName = "System.Int16";
        public const string SystemIntTypeFullName = "System.Int32";
        public const string SystemLongTypeFullName = "System.Int64";
        public const string SystemByteTypeFullName = "System.Byte";
        public const string SystemFloatTypeFullName = "System.Single";
        public const string SystemDoubleTypeFullName = "System.Double";

        public const string GlobalSystemStringTypeFullName = "global::System.String";
        public const string GlobalSystemShortTypeFullName = "global::System.Int16";
        public const string GlobalSystemIntTypeFullName = "global::System.Int32";
        public const string GlobalSystemLongTypeFullName = "global::System.Int64";
        public const string GlobalSystemByteTypeFullName = "global::System.Byte";
        public const string GlobalSystemFloatTypeFullName = "global::System.Single";
        public const string GlobalSystemDoubleTypeFullName = "global::System.Double";

        public const string SystemNullableTypeFullName = "System.Nullable";
        public const string SystemListTypeFullName = "System.Collections.Generic.List";
        public const string SystemListInterfaceTypeFullName = "System.Collections.Generic.IList";
        public const string SystemDictionaryTypeFullName = "System.Collections.Generic.Dictionary";
        public const string SystemDictionaryInterfaceTypeFullName = "System.Collections.Generic.IDictionary";

        public const string GlobalSystemNullableTypeFullName = "global::System.Nullable";
        public const string GlobalSystemListTypeFullName = "global::System.Collections.Generic.List";
        public const string GlobalSystemListInterfaceTypeFullName = "global::System.Collections.Generic.IList";
        public const string GlobalSystemDictionaryTypeFullName = "global::System.Collections.Generic.Dictionary";
        public const string GlobalSystemDictionaryInterfaceTypeFullName = "global::System.Collections.Generic.IDictionary";

        public const string GlobalNamespace = "<global namespace>";

        public static readonly string[] BasicValueTypeNames = new string[]
        {
            "string",
            "byte",
            "sbyte",
            "char",
            "short",
            "ushort",
            "int",
            "uint",
            "long",
            "ulong",
            "float",
            "double",
            "decimal",
            "bool",
        };


        /// <summary>
        /// 如果类型名是基础类型，返回<see langword="true"/>
        /// </summary>
        public static bool IsBasicValueTypeDisplayName(string typeName)
        {
            if (typeName.EndsWith("?"))
            {
                typeName = typeName.Substring(0, typeName.Length - 1);
            }

            return Array.Exists(BasicValueTypeNames, e => e == typeName);
        }


        /// <summary>
        /// 如果类型是 System.Collections.Generic.IList 或 System.Collections.Generic.List，
        /// 返回<see langword="true"/>。
        /// </summary>
        public static bool IsListDisplayName(string typeName)
        {
            if (typeName.StartsWith("global"))
            {
                return typeName.StartsWith(GlobalSystemListInterfaceTypeFullName)
                    || typeName.StartsWith(GlobalSystemListTypeFullName);
            }

            return typeName.StartsWith(SystemListInterfaceTypeFullName)
                || typeName.StartsWith(SystemListTypeFullName);
        }


        /// <summary>
        /// 如果类型是 System.Collections.Generic.IDictionary 或 System.Collections.Generic.Dictionary，
        /// 返回<see langword="true"/>。
        /// </summary>
        public static bool IsDictionaryDisplayName(string typeName)
        {
            if (typeName.StartsWith("global"))
            {
                return typeName.StartsWith(GlobalSystemDictionaryInterfaceTypeFullName)
                    || typeName.StartsWith(GlobalSystemDictionaryTypeFullName);
            }

            return typeName.StartsWith(SystemDictionaryInterfaceTypeFullName)
                || typeName.StartsWith(SystemDictionaryTypeFullName);
        }


        /// <summary>
        /// 将<see cref="IList{T}"/>替换成<see cref="List{T}"/>或
        /// 将<see cref="IDictionary{TKey, TValue}"/>替换成<see cref="Dictionary{TKey, TValue}"/>
        /// 并返回。
        /// </summary>
        public static string GetImplementTypeName(string fullName)
        {
            // IList
            if (fullName.StartsWith(GlobalSystemListInterfaceTypeFullName))
            {
                return fullName.Replace(GlobalSystemListInterfaceTypeFullName, GlobalSystemListTypeFullName);
            }

            if (fullName.StartsWith(SystemListInterfaceTypeFullName))
            {
                return fullName.Replace(SystemListInterfaceTypeFullName, SystemListTypeFullName);
            }

            // IDictionary
            if (fullName.StartsWith(GlobalSystemDictionaryInterfaceTypeFullName))
            {
                return fullName.Replace(GlobalSystemDictionaryInterfaceTypeFullName, GlobalSystemDictionaryTypeFullName);
            }

            if (fullName.StartsWith(SystemDictionaryInterfaceTypeFullName))
            {
                return fullName.Replace(SystemDictionaryInterfaceTypeFullName, SystemDictionaryTypeFullName);
            }

            return fullName;
        }


        /// <summary>
        /// 获取指定名称的属性或字段，如果不存在，返回<see langword="false"/>
        /// </summary>
        public static bool TryGetTypePropertySymbol(ITypeSymbol typeSymbol, string propertyName, out IPropertySymbol property, out IFieldSymbol field)
        {
            property = null;
            field = null;

            if (typeSymbol == null || string.IsNullOrEmpty(propertyName))
            {
                return false;
            }

            foreach (var member in typeSymbol.GetMembers(propertyName))
            {
                switch (member)
                {
                    case IPropertySymbol propertySymbol:
                        property = propertySymbol;
                        return true;

                    case IFieldSymbol fieldSymbol:
                        field = fieldSymbol;
                        return true;

                    default:
                        break;
                }
            }

            return false;
        }


        /// <summary>
        /// 获取类型中指定名称属性或字段的类型，如果指定名称不存在或者不是属性或字段，返回<see langword="null"/>
        /// </summary>
        public static ITypeSymbol GetTypePropertyTypeFullName(ITypeSymbol typeSymbol, string propertyName)
        {
            if (typeSymbol == null || string.IsNullOrEmpty(propertyName))
            {
                return null;
            }

            foreach (var member in typeSymbol.GetMembers(propertyName))
            {
                switch (member)
                {
                    case IPropertySymbol propertySymbol:
                        return propertySymbol.Type;

                    case IFieldSymbol fieldSymbol:
                        return fieldSymbol.Type;

                    default:
                        break;
                }
            }

            return null;
        }



        public static bool TryGetListGenericArgument(ITypeSymbol symbol, out ITypeSymbol genericSymbol)
        {
            genericSymbol = null;

            if (symbol is INamedTypeSymbol namedTypeSymbol &&
                IsListDisplayName(symbol.ToDisplayString()) &&
                namedTypeSymbol.TypeArguments.Length == 1)
            {
                genericSymbol = namedTypeSymbol.TypeArguments[0];
                return true;
            }

            return false;
        }


        public static bool TryGetDictionaryGenericArguments(ITypeSymbol symbol, out ITypeSymbol keySymbol, out ITypeSymbol valueSymbol)
        {
            keySymbol = null;
            valueSymbol = null;

            if (symbol is INamedTypeSymbol namedTypeSymbol &&
                IsDictionaryDisplayName(namedTypeSymbol.ToDisplayString()) &&
                namedTypeSymbol.TypeArguments.Length == 2)
            {
                keySymbol = namedTypeSymbol.TypeArguments[0];
                valueSymbol = namedTypeSymbol.TypeArguments[1];
                return true;
            }

            return false;
        }

    }

}